package com.server;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashSet;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class AndroidServer {

	private String myName = null;
	private static String userDirectory = "C:\\Users\\Varun\\workspace\\AndroidServer";
	private static String xmlFileExtension = ".xml";
	private static String pathSeparator = "\\";
	private static String userNameTag = "UserName";
	private static String friendListTag = "FriendList";
	private static String friendNameTag = "FriendName";
	

	public AndroidServer(String name) {
		this.myName = name;
	}

	/**
	 * Registers a user with the server by creating an xml file by the name
	 * user_name.xml. If the user already exists, returns error code 1
	 * @param name - name of the user being registered
	 * @return 0 if the user is registered successfully, 1 if the user already 
	 * exists.
	 * @throws FileNotFoundException
	 * @throws XMLStreamException
	 */
	public int RegisterUser(String name) throws FileNotFoundException, XMLStreamException
	{
		if(!UserExists(name))
		{
			XMLOutputFactory xof = XMLOutputFactory.newInstance();
			XMLStreamWriter xtw = null;
			String userFilePath = GetUserFilePath(name);
			xtw = xof.createXMLStreamWriter(new FileOutputStream(userFilePath), "UTF-8");
			
			xtw.writeStartDocument("utf-8", "1.0");
			xtw.writeStartElement(userNameTag);
			xtw.writeCharacters(name);
			xtw.writeStartElement(friendListTag);
			xtw.writeEndElement();
			xtw.writeEndElement();
			xtw.writeEndDocument();
			xtw.writeEndDocument();
			xtw.flush();
			xtw.close();	
			return 0;
		}
		else
		{
			//User already exists. Return error code 1
			return 1;
		}
	}
	
	/**
	 * Method to check if a user already exists (if a xml file for the user 
	 * exists)
	 * @param userName
	 * @return true if user exists, false otherwise
	 */
	private boolean UserExists(String userName)
	{
		String filePath = userDirectory+pathSeparator+userName+xmlFileExtension;
		File userFile = new File(filePath);
		if(userFile.exists())
			return true;
		else return false;
	}
	
	/**
	 * Utility method to get the user xml file path name
	 * @param userName
	 * @return xml file path 
	 */
	private String GetUserFilePath(String userName)
	{
		return userDirectory+pathSeparator+userName+xmlFileExtension;
	}
	
	/**
	 * Checks if a friend exists in the users friend list
	 * @param userName 
	 * @param friendName
	 * @return true if the friend exists, false otherwise
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 */
	public boolean FriendExists(String userName, String friendName) throws ParserConfigurationException, SAXException, IOException
	{
		HashSet<String> friendList = GetFriendList(userName);
		if(friendList.contains(friendName))
		{
			return true;
		}
		else return false;
	}
	
	/**
	 * Gets the friend list of a user
	 * @param userName
	 * @return the friend list as a HashSet
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 */
	public HashSet<String> GetFriendList(String userName) throws ParserConfigurationException, SAXException, IOException
	{
		HashSet<String> friendList = new HashSet<String>();
		if(UserExists(userName))
		{	
			Node node;
			String nodeText;
			String userFilePath = GetUserFilePath(userName);
			DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
			Document doc = docBuilder.parse(userFilePath);
			
			Node friendListNode = doc.getElementsByTagName(friendListTag).item(0);
			NodeList friends = friendListNode.getChildNodes();
			for(int i=0;i<friends.getLength();i++)
			{
				node = friends.item(i);
				nodeText = node.getTextContent();
				friendList.add(nodeText);
			}
		}
		else
		{
			//User does not exist. Print to the log
		}
		return friendList;		
	}
	
	/**
	 * Adds a friend to the users's friend list.
	 * does not check if a user is registered. It is up to the app to check 
	 * if the user is registered.
	 * @param user
	 * @param friendName
	 * @return 0 if the friend is added, 1 if the friend already exists in
	 * the friend list
	 * @throws SAXException
	 * @throws IOException
	 * @throws ParserConfigurationException
	 * @throws TransformerException
	 */
	public int AddFriend(String user, String friendName) throws SAXException, IOException, ParserConfigurationException, TransformerException
 {
		if (!FriendExists(user, friendName)) {
			String userFilePath = GetUserFilePath(user);
			DocumentBuilderFactory docFactory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
			Document doc = docBuilder.parse(userFilePath);

			// Get the FriendList element
			Node friendList = doc.getElementsByTagName(friendListTag).item(0);

			// Create new node with tag FRIEND NAME
			Element newFriend = doc.createElement(friendNameTag);
			// add the parameter name as the value for the new node
			newFriend.appendChild(doc.createTextNode(friendName));
			// Make the new node a child of FriendList
			friendList.appendChild(newFriend);

			// write the content into xml file
			TransformerFactory transformerFactory = TransformerFactory
					.newInstance();
			Transformer transformer = transformerFactory.newTransformer();
			DOMSource source = new DOMSource(doc);
			StreamResult result = new StreamResult(new File(userFilePath));
			transformer.transform(source, result);
			return 0;
		} else {
			// Friend already exists. Return error code 1
			return 1;
		}
	}
}
